package br.cnpq.webflowah.beans;

import java.io.FileOutputStream;
import java.io.Serializable;
import java.net.URI;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Stack;

import javax.swing.tree.DefaultMutableTreeNode;
import javax.swing.tree.TreeModel;
import javax.swing.tree.TreeNode;

import org.mindswap.owl.EntityFactory;
import org.mindswap.owl.OWLDataProperty;
import org.mindswap.owl.OWLDataValue;
import org.mindswap.owl.OWLIndividual;
import org.mindswap.owl.OWLKnowledgeBase;
import org.mindswap.owl.OWLObjectProperty;
import org.mindswap.owl.OWLOntology;
import org.mindswap.owl.OWLType;
import org.mindswap.owl.vocabulary.XSD;
import org.mindswap.owls.process.Choice;
import org.mindswap.owls.process.CompositeProcess;
import org.mindswap.owls.process.Condition;
import org.mindswap.owls.process.ControlConstruct;
import org.mindswap.owls.process.IfThenElse;
import org.mindswap.owls.process.Input;
import org.mindswap.owls.process.InputList;
import org.mindswap.owls.process.Local;
import org.mindswap.owls.process.Output;
import org.mindswap.owls.process.OutputList;
import org.mindswap.owls.process.Perform;
import org.mindswap.owls.process.Process;
import org.mindswap.owls.process.RepeatWhile;
import org.mindswap.owls.process.Result;
import org.mindswap.owls.process.Sequence;
import org.mindswap.owls.process.SplitJoin;
import org.mindswap.swrl.Atom;
import org.mindswap.swrl.AtomList;
import org.mindswap.swrl.SWRLDataObject;
import org.mindswap.swrl.SWRLDataValue;
import org.mindswap.swrl.SWRLDataVariable;
import org.mindswap.swrl.SWRLFactory;
import org.mindswap.swrl.SWRLFactoryCreator;
import org.mindswap.utils.URIUtils;

import br.cnpq.webflowah.ontologia.Repositorio;

public class PlanoExecucao implements Serializable {

	private static int contador = 1;

	private static final long serialVersionUID = 1L;

	public final static String BASE_URL = "http://localhost/webflowah/1.0/PlanoExecucao.owl";

	public final static String BASE_URI = BASE_URL + "#";

	private static int rdfID;

	private OWLKnowledgeBase kb;

	private OWLOntology ont;

	private SWRLFactory swrl = null;

	private CompositeProcess composite;

	private Sequence sequence;

	private class Resultado {

		public OWLType paramType;

		public Output output;

		public Perform perform;

		public String label;

		public boolean usado;

		public Resultado(Output o, Perform p, String s) {
			this.output = o;
			this.perform = p;
			this.paramType = o.getParamType();
			this.label = s;
			this.usado = false;
		}

	}

	private List<Operacao> operacoes = null;

	public List<Operacao> getOperacoes() {
		return operacoes;
	}




	private int lastOperacao;

//	private Map<URI, Resultado> resultadosMap = new HashMap<URI, Resultado>();

	private Stack<Process> processos = new Stack<Process>();

	private Stack<Map<URI, Resultado>> resultados = new Stack<Map<URI, Resultado>>();

	private Stack<Map<URI, URI>> deParaInput = new Stack<Map<URI, URI>>();

	private Stack<Map<URI, URI>> deParaOutput = new Stack<Map<URI, URI>>();

	private Map<URI, URI> entradas = null;

	private Map<URI, URI> saidas = null;

	public PlanoExecucao() {
		rdfID = 1;
		lastOperacao = 0;
		kb = Repositorio.newInstance(false);
		ont = kb.createOntology(URI.create(BASE_URL));
		swrl = SWRLFactoryCreator.createFactory();
		sequence = ont.createSequence(URI.create(BASE_URI + "Sequence_" + rdfID++));
		composite = ont.createCompositeProcess(URI.create(BASE_URI + "Composite_" + rdfID++));
		composite.setComposedOf(sequence);
		processos.push(composite);
		resultados.push(new HashMap<URI, Resultado>());
		deParaInput.push(new HashMap<URI, URI>());
		deParaOutput.push(new HashMap<URI, URI>());
	}

	public Process getProcess() {
		return this.composite;
	}

	public void setOperacoes(List<Operacao> list) {
		this.operacoes = list;
	}

	private Operacao[] getOperacoes(Objetivo objetivo) {
		List<Operacao> list = new ArrayList<Operacao>();

		for (int i=lastOperacao; i < operacoes.size(); i++) {
			Operacao operacao = operacoes.get(i);
			list.add(operacao);
			lastOperacao++;
			if (operacao.getObjetivo().equals(objetivo))
				break;
		}

		return list.toArray(new Operacao[0]);
	}

//	public void addOperacao(Process processo, Operacao operacao) {
//		Perform perform = ont.createPerform();
//		perform.setProcess(processo);
//
//		Iterator iter = processo.getInputs().iterator();
//		while (iter.hasNext()) {
//			Input input1 = (Input) iter.next();
//			// obtem o conceito objeto da entrada
//			URI key = operacao.getEntrada(input1.getURI());
//			// obtem a operacao e a saida
//			Resultado resultado = resultadosMap.get(key);
//			if (resultado != null) {
//				// cria ligacao entre a entrada e a saida
//				perform.addBinding(input1, resultado.perform, resultado.output);
//				// remove da lista de resultados
//				resultadosMap.remove(key);
//			} else {
//				// cria entrada do plano
//				Input input2 = process.createInput(URI.create(URIUtils.getLocalName(key)),
//						input1.getParamType());
//				// cria ligacao entre a entrada da operacao e a entrada do plano
//				perform.addBinding(input1, Perform.TheParentPerform, input2);
//			}
//		}
//
//		iter = processo.getOutputs().iterator();
//		while (iter.hasNext()) {
//			Output output1 = (Output) iter.next();
//			URI key = operacao.getSaida(output1.getURI());
//			// adiciona como provavel resultado
//			resultadosMap.put(key, new Resultado(output1, perform));
//		}
//
//		sequence.addComponent(perform);
//		ont.addImport(processo.getOntology());
//		kb.load(processo.getOntology());
//	}

	public InputList getEntradas() {
		return composite.getInputs();
	}

	public String getEntrada(URI uri) {
		return "" + entradas.get(uri);
	}

	public OutputList getSaidas() {
		return composite.getOutputs();
	}

	public String getSaida(URI uri) {
		return "" + saidas.get(uri);
	}

	public OWLIndividual getIndividual(String uri) {
		return kb.getIndividual(URI.create(uri));
	}

//	public void complete() {
//		Result result = process.createResult();
//		Iterator iter = resultadosMap.keySet().iterator();
//		while (iter != null && iter.hasNext()) {
//			URI key = (URI) iter.next();
//			Resultado resultado = resultadosMap.get(key);
//			Output output2 = process.createOutput(URI.create(URIUtils.getLocalName(key)), resultado.paramType);
//			result.addBinding(output2, resultado.perform, resultado.output);
//		}
////		ont.write(System.out);
//	}

	private Input getInput(String arg0, Process process) {
		Map<URI, URI> depara1 = deParaInput.peek();
		InputList inputList = process.getInputs();
		for (int i=0; inputList != null && i < inputList.size(); i++) {
			URI uri = depara1.get(inputList.inputAt(i).getURI());
			if (arg0.equals(uri.toString())) return inputList.inputAt(i);
		}

		return null;
	}

	private Input getInputVar(Conceito var, Process process) {
		Input input = getInput(var.getURI(), process);

		if (input != null) return input;

		input = process.createInput(URI.create(BASE_URI + "Input_" + rdfID++),
				ont.getType(URI.create(var.getAnotacao())));
		input.setLabel(var.getNome() + " (" + var.getNome() + ")");
		Map<URI, URI> depara1 = deParaInput.peek();
		depara1.put(input.getURI(), URI.create(var.getURI()));

		return input;
	}

//	private Input getInputVar(String arg0) {
//		// procura no processo atual se existe a entrada
//		Input input = getInput(arg0, processos.peek());
//		if (input != null) return input;
//
//		// procura em que processo existe a entrada
//		Object[] array = processos.toArray();
//		for (int i=0; i < array.length; i++) {
//			input = getInput(arg0, (Process) array[i]);
//			if (input != null) {
//				for (int j=i+1; j < array.length; j++) {
//					Process p = (Process) array[j];
////					Input novo = p.createInput(uri, paramType)
//				}
//			}
//		}
//
//		// procura em que resultado existe a entrada
//
//		return null;
//	}

	private Atom criarAtom(Expressao expressao) {
		Conceito variavel = expressao.getVariavel();
		Conceito operador = expressao.getOperador();
		Conceito valor = expressao.getValor();
		Conceito propriedade = expressao.getPropriedade();

		if (operador.getURI().equals(Expressao.URI_EQUAL) && propriedade == null) {
			Input input = getInputVar(variavel, processos.peek());
			OWLDataValue value = EntityFactory.createDataValue(valor.getNome());
			return swrl.createEqual(
					(SWRLDataObject) input.castTo(SWRLDataVariable.class),
					(SWRLDataValue) value.castTo(SWRLDataValue.class));
		} else if (operador.getURI().equals(Expressao.URI_NOT_EQUAL) && propriedade == null) {
			Input input = getInputVar(variavel, processos.peek());
			OWLDataValue value = EntityFactory.createDataValue(valor.getNome());
			return swrl.createNotEqual(
					(SWRLDataObject) input.castTo(SWRLDataVariable.class),
					(SWRLDataValue) value.castTo(SWRLDataValue.class));
		} else if (operador.getURI().equals(Expressao.URI_GREATER_THAN) && propriedade == null) {
			Input input = getInputVar(variavel, processos.peek());
			OWLDataValue value = EntityFactory.createDataValue(valor.getNome());
			return swrl.createGreaterThan(
					(SWRLDataObject) input.castTo(SWRLDataVariable.class),
					(SWRLDataValue) value.castTo(SWRLDataValue.class));
		} else if (operador.getURI().equals(Expressao.URI_GREATER_THAN_EQUAL) && propriedade == null) {
			Input input = getInputVar(variavel, processos.peek());
			OWLDataValue value = EntityFactory.createDataValue(valor.getNome());
			return swrl.createGreaterThanOrEqual(
					(SWRLDataObject) input.castTo(SWRLDataVariable.class),
					(SWRLDataValue) value.castTo(SWRLDataValue.class));
		} else if (operador.getURI().equals(Expressao.URI_LESS_THAN) && propriedade == null) {
			Input input = getInputVar(variavel, processos.peek());
			OWLDataValue value = EntityFactory.createDataValue(valor.getNome());
			return swrl.createLessThan(
					(SWRLDataObject) input.castTo(SWRLDataVariable.class),
					(SWRLDataValue) value.castTo(SWRLDataValue.class));
		} else if (operador.getURI().equals(Expressao.URI_LESS_THAN_EQUAL) && propriedade == null) {
			Input input = getInputVar(variavel, processos.peek());
			OWLDataValue value = EntityFactory.createDataValue(valor.getNome());
			return swrl.createLessThanOrEqual(
					(SWRLDataObject) input.castTo(SWRLDataVariable.class),
					(SWRLDataValue) value.castTo(SWRLDataValue.class));
		} else if (operador.getURI().equals(Expressao.URI_SAME) && propriedade == null) {
			Input input = getInputVar(variavel, processos.peek());
		    OWLIndividual ind2 = kb.getIndividual(URI.create(valor.getURI()));
			return swrl.createSameIndividualAtom(input, ind2);
		} else if (operador.getURI().equals(Expressao.URI_DIFF) && propriedade == null) {
			Input input = getInputVar(variavel, processos.peek());
		    OWLIndividual ind2 = kb.getIndividual(URI.create(valor.getURI()));
			return swrl.createDifferentIndividualsAtom(input, ind2);
		} else if (propriedade != null && propriedade.isTipoPrimitivo()) {
			Process process = processos.peek();
			Input input = getInputVar(variavel, process);
		    OWLDataProperty prop = kb.getDataProperty(URI.create(propriedade.getURI()));
		    OWLDataValue value = EntityFactory.createDataValue(valor.getNome(), XSD.string);
//			OWLDataValue value = EntityFactory.createDataValue(valor.getNome());
			// cria a precondicao para armazenar o valor da propriedade em uma variavel local
		    Local local = process.createLocal(URI.create(BASE_URI + "Local_" + rdfID++), kb.getType(XSD.string));
			Condition condition = ont.createSWRLCondition(URI.create(BASE_URI + "Precondition_" + rdfID++));
			Atom atom = swrl.createDataPropertyAtom(prop, input, local);
			AtomList body = swrl.createList(atom);
			condition.setBody(body);
			process.addCondition(condition);
			// cria a condicao
			if (operador.getURI().equals(Expressao.URI_EQUAL)) {
				return swrl.createEqual(
						(SWRLDataObject) local.castTo(SWRLDataVariable.class),
						(SWRLDataValue) value.castTo(SWRLDataValue.class));
			} else if (operador.getURI().equals(Expressao.URI_NOT_EQUAL)) {
				return swrl.createNotEqual(
						(SWRLDataObject) local.castTo(SWRLDataVariable.class),
						(SWRLDataValue) value.castTo(SWRLDataValue.class));
			} else if (operador.getURI().equals(Expressao.URI_GREATER_THAN)) {
				return swrl.createGreaterThan(
						(SWRLDataObject) local.castTo(SWRLDataVariable.class),
						(SWRLDataValue) value.castTo(SWRLDataValue.class));
			} else if (operador.getURI().equals(Expressao.URI_GREATER_THAN_EQUAL)) {
				return swrl.createGreaterThanOrEqual(
						(SWRLDataObject) local.castTo(SWRLDataVariable.class),
						(SWRLDataValue) value.castTo(SWRLDataValue.class));
			} else if (operador.getURI().equals(Expressao.URI_LESS_THAN)) {
				return swrl.createLessThan(
						(SWRLDataObject) local.castTo(SWRLDataVariable.class),
						(SWRLDataValue) value.castTo(SWRLDataValue.class));
			} else if (operador.getURI().equals(Expressao.URI_LESS_THAN_EQUAL)) {
				return swrl.createLessThanOrEqual(
						(SWRLDataObject) local.castTo(SWRLDataVariable.class),
						(SWRLDataValue) value.castTo(SWRLDataValue.class));
			} else {
				return null;
			}
		} else if (propriedade != null && !propriedade.isTipoPrimitivo()) {
			Process process = processos.peek();
			Input input = getInputVar(variavel, process);
		    OWLObjectProperty prop = kb.getObjectProperty(URI.create(propriedade.getURI()));
		    OWLIndividual ind2 = kb.getIndividual(URI.create(valor.getURI()));
			// cria a precondicao para armazenar o valor da propriedade em uma variavel local
		    Local local = process.createLocal(URI.create(BASE_URI + "Local_" + rdfID++), ind2.getType());
			Condition condition = ont.createSWRLCondition(URI.create(BASE_URI + "Precondition_" + rdfID++));
			Atom atom = swrl.createIndividualPropertyAtom(prop, input, local);
			AtomList body = swrl.createList(atom);
			condition.setBody(body);
			process.addCondition(condition);
			// cria condicao
			if (operador.getURI().equals(Expressao.URI_SAME)) {
				return swrl.createSameIndividualAtom(local, ind2);
			} else if (operador.getURI().equals(Expressao.URI_DIFF)) {
				return swrl.createDifferentIndividualsAtom(local, ind2);
			} else {
				return null;
			}
		} else {
			return null;
		}
	}



	public ControlConstruct criarComponente(TreeNode arg0) throws Exception {
		if (arg0 == null) return null;

		ControlConstruct cc = null;
		DefaultMutableTreeNode node = (DefaultMutableTreeNode) arg0;

		if ("Sequ�ncia".equals(node.getUserObject())) {
			Sequence sequence = ont.createSequence(URI.create(BASE_URI + "Sequence_" + rdfID++));
			for (int i=0; i < node.getChildCount(); i++) {
				ControlConstruct cc1 = criarComponente(node.getChildAt(i));
				sequence.addComponent(cc1);
			}
			cc = sequence;
		} else if ("Divis�o+Jun��o".equals(node.getUserObject())) {
			SplitJoin split = ont.createSplitJoin(URI.create(BASE_URI + "SplitJoin_" + rdfID++));
			for (int i=0; i < node.getChildCount(); i++) {
				ControlConstruct cc1 = criarComponente(node.getChildAt(i));
				split.addComponent(cc1);
			}
			cc = split;
		} else if ("Escolha".equals(node.getUserObject())) {
			Choice choice = ont.createChoice(URI.create(BASE_URI + "Choice_" + rdfID++));
			for (int i=0; i < node.getChildCount(); i++) {
				ControlConstruct cc1 = criarComponente(node.getChildAt(i));
				choice.addComponent(cc1);
			}
			cc = choice;
		} else if (node.getUserObject() instanceof Objetivo) {
			Process process = processos.peek();
//			Map<URI, Ligacao> inputsMap = entradas.peek();
			Map<URI, Resultado>	resultsMap = resultados.peek();
			Map<URI, URI> depara1 = deParaInput.peek();
			Sequence sequence = ont.createSequence(URI.create(BASE_URI + "Sequence_" + rdfID++));

			// obter a operacao
			Operacao[] caminho = getOperacoes((Objetivo) node.getUserObject());

			for (int i=0; i < caminho.length; i++) {
				Operacao operacao = caminho[i];

				Process atomic = operacao.getProcess();

				Perform perform = ont.createPerform(URI.create(BASE_URI + "Perform_" + rdfID++));
				perform.setProcess(atomic);

				Iterator iter = atomic.getInputs().iterator();
				while (iter.hasNext()) {
					Input input1 = (Input) iter.next();
					// obtem o conceito objeto da entrada
					URI key = operacao.getEntrada(input1.getURI());
					// obtem a operacao e a saida
					Resultado resultado = resultsMap.get(key);
					if (resultado != null) {
						// cria ligacao entre a entrada e a saida
						perform.addBinding(input1, resultado.perform, resultado.output);
						// remove da lista de resultados
//						resultsMap.remove(key);
						resultado.usado = true;
					} else {
						Input input2 = getInput(key.toString(), process);

						if (input2 != null)
							perform.addBinding(input1, Perform.TheParentPerform, input2);
						else {
							// cria entrada do plano
							input2 = process.createInput(URI.create(BASE_URI + "Input_" + rdfID++),
									input1.getParamType());
							input2.setLabel(URIUtils.getLocalName(key) + " (" + input1.getLocalName() + ")");
							depara1.put(input2.getURI(), key);
							// cria ligacao entre a entrada da operacao e a entrada do plano
							perform.addBinding(input1, Perform.TheParentPerform, input2);
						}
					}
				}

				iter = atomic.getOutputs().iterator();
				while (iter.hasNext()) {
					Output output1 = (Output) iter.next();
					URI key = operacao.getSaida(output1.getURI());
					String label = URIUtils.getLocalName(key) + " (" + output1.getLocalName() + ")";
					// adiciona como provavel resultado
					resultsMap.put(key, new Resultado(output1, perform, label));
				}

				sequence.addComponent(perform);
				ont.addImport(atomic.getOntology());
				kb.load(atomic.getOntology());
			}

			cc = sequence;
		} else if (node.getUserObject() instanceof Repeticao) {
			CompositeProcess composite = ont.createCompositeProcess(URI.create(BASE_URI + "Composite_" + rdfID++));
			RepeatWhile repeatWhile = ont.createRepeatWhile(URI.create(BASE_URI + "RepeatWhile_" + rdfID++));
			composite.setComposedOf(repeatWhile);
			Perform perform = ont.createPerform(URI.create(BASE_URI + "Perform_" + rdfID++));
			perform.setProcess(composite);

			processos.push(composite);
			resultados.push(new HashMap<URI, Resultado>());
			deParaInput.push(new HashMap<URI, URI>());
			deParaOutput.push(new HashMap<URI, URI>());

			ControlConstruct cc1 = (node.getChildCount() > 0)
				? criarComponente(node.getFirstChild())
				: null;
			if (cc1 != null) repeatWhile.setComponent(cc1);

			// cria a condicao
			Condition condition = ont.createSWRLCondition(URI.create(BASE_URI + "Condition_" + rdfID++));
			Repeticao repeticao = (Repeticao) node.getUserObject();
			List expressoes = repeticao.getExpressoes();
			AtomList atomList = (expressoes != null && expressoes.size() > 0)
				? swrl.createList(criarAtom((Expressao) expressoes.get(0))) : null;
			for (int i=1; expressoes != null && i < expressoes.size(); i++) {
				Expressao expressao = (Expressao) expressoes.get(i);
				atomList.add(criarAtom(expressao));
			}
			condition.setBody(atomList);
			repeatWhile.setCondition(condition);

			// criar os results
			Process process = processos.pop();
			Map<URI, Resultado>	resultsMap = resultados.pop();
			Map<URI, URI> depara1 = deParaInput.pop();
			Map<URI, URI> depara2 = deParaOutput.pop();

			Result result = process.createResult();
			Iterator iter = resultsMap.keySet().iterator();
			while (iter != null && iter.hasNext()) {
				URI key = (URI) iter.next();
				Resultado resultado = resultsMap.get(key);
				if (resultado.usado) continue;
				Output output2 = process.createOutput(URI.create(BASE_URI + "Output_" + rdfID++), resultado.paramType);
				output2.setLabel(resultado.label);
				depara2.put(output2.getURI(), key);
				result.addBinding(output2, resultado.perform, resultado.output);
			}

			// ligar com os parametros externos
			process = processos.peek();
			resultsMap = resultados.peek();
			Map<URI, URI> depara = deParaInput.peek();

			iter = composite.getInputs().iterator();
			while (iter.hasNext()) {
				Input input1 = (Input) iter.next();
				// obtem o conceito objeto da entrada
				URI key = depara1.get(input1.getURI());
				// obtem a operacao e a saida
				Resultado resultado = resultsMap.get(key);
				if (resultado != null) {
					// cria ligacao entre a entrada e a saida
					perform.addBinding(input1, resultado.perform, resultado.output);
					// remove da lista de resultados
//					resultsMap.remove(key);
					resultado.usado = true;
				} else {
//					Input input2 = getInput(key.toString(), process);
//
//					if (input2 != null)
//						perform.addBinding(input1, Perform.TheParentPerform, input2);
//					else {
						// cria entrada do plano
					Input input2 = process.createInput(URI.create(BASE_URI + "Input_" + rdfID++),
								input1.getParamType());
						input2.setLabel(input1.getLabel());
						depara.put(input2.getURI(), key);
						// cria ligacao entre a entrada da operacao e a entrada do plano
						perform.addBinding(input1, Perform.TheParentPerform, input2);
//					}
				}
			}

			iter = composite.getOutputs().iterator();
			while (iter.hasNext()) {
				Output output1 = (Output) iter.next();
				URI key = depara2.get(output1.getURI());
				// adiciona como provavel resultado
				resultsMap.put(key, new Resultado(output1, perform, output1.getLabel()));
			}

			cc = perform;
		} else if (node.getUserObject() instanceof Condicao) {
			CompositeProcess composite = ont.createCompositeProcess(URI.create(BASE_URI + "Composite_" + rdfID++));
			IfThenElse ifThenElse = ont.createIfThenElse(URI.create(BASE_URI + "IfThenElse_" + rdfID++));
			composite.setComposedOf(ifThenElse);
			Perform perform = ont.createPerform(URI.create(BASE_URI + "Perform_" + rdfID++));
			perform.setProcess(composite);

			processos.push(composite);
			resultados.push(new HashMap<URI, Resultado>());
			deParaInput.push(new HashMap<URI, URI>());
			deParaOutput.push(new HashMap<URI, URI>());

			ControlConstruct cc1 = (node.getChildCount() > 0)
				? criarComponente(node.getFirstChild())
				: null;
			ControlConstruct cc2 = (node.getChildCount() > 1)
				? criarComponente(node.getLastChild())
				: null;
			if (cc1 != null) ifThenElse.setThen(cc1);
			if (cc2 != null) ifThenElse.setElse(cc2);

			// cria a condicao
			Condition condition = ont.createSWRLCondition(URI.create(BASE_URI + "Condition_" + rdfID++));
			Condicao condicao = (Condicao) node.getUserObject();
			List expressoes = condicao.getExpressoes();
			AtomList atomList = (expressoes != null && expressoes.size() > 0)
				? swrl.createList(criarAtom((Expressao) expressoes.get(0))) : null;
			for (int i=1; expressoes != null && i < expressoes.size(); i++) {
				Expressao expressao = (Expressao) expressoes.get(i);
				atomList.add(criarAtom(expressao));
			}
			condition.setBody(atomList);
			ifThenElse.setCondition(condition);

			// criar os results
			Process process = processos.pop();
			Map<URI, Resultado>	resultsMap = resultados.pop();
			Map<URI, URI> depara1 = deParaInput.pop();
			Map<URI, URI> depara2 = deParaOutput.pop();

			Result result = process.createResult();
			Iterator iter = resultsMap.keySet().iterator();
			while (iter != null && iter.hasNext()) {
				URI key = (URI) iter.next();
				Resultado resultado = resultsMap.get(key);
				if (resultado.usado) continue;
				Output output2 = process.createOutput(URI.create(BASE_URI + "Output_" + rdfID++), resultado.paramType);
				output2.setLabel(resultado.label);
				depara2.put(output2.getURI(), key);
				result.addBinding(output2, resultado.perform, resultado.output);
			}

			// ligar com os parametros externos
			process = processos.peek();
			resultsMap = resultados.peek();
			Map<URI, URI> depara = deParaInput.peek();

			iter = composite.getInputs().iterator();
			while (iter.hasNext()) {
				Input input1 = (Input) iter.next();
				// obtem o conceito objeto da entrada
				URI key = depara1.get(input1.getURI());
				// obtem a operacao e a saida
				Resultado resultado = resultsMap.get(key);
				if (resultado != null) {
					// cria ligacao entre a entrada e a saida
					perform.addBinding(input1, resultado.perform, resultado.output);
					// remove da lista de resultados
//					resultsMap.remove(key);
					resultado.usado = true;
				} else {
//					Input input2 = getInput(key.toString(), process);
//
//					if (input2 != null)
//						perform.addBinding(input1, Perform.TheParentPerform, input2);
//					else {
						// cria entrada do plano
					Input input2 = process.createInput(URI.create(BASE_URI + "Input_" + rdfID++),
								input1.getParamType());
						input2.setLabel(input1.getLabel());
						depara.put(input2.getURI(), key);
						// cria ligacao entre a entrada da operacao e a entrada do plano
						perform.addBinding(input1, Perform.TheParentPerform, input2);
//					}
				}
			}

			iter = composite.getOutputs().iterator();
			while (iter.hasNext()) {
				Output output1 = (Output) iter.next();
				URI key = depara2.get(output1.getURI());
				// adiciona como provavel resultado
				resultsMap.put(key, new Resultado(output1, perform, output1.getLabel()));
			}

			cc = perform;
		}

		return cc;
	}




	public void criar(TreeModel model) throws Exception {
		DefaultMutableTreeNode root = (DefaultMutableTreeNode) model.getRoot();

		for (int i=0; i < root.getChildCount(); i++) {
			ControlConstruct child = criarComponente(root.getChildAt(i));
			sequence.addComponent(child);
		}

		Process process = processos.pop();
		Map<URI, Resultado>	resultsMap = resultados.pop();
		entradas = deParaInput.pop();
		saidas = deParaOutput.pop();

		Result result = process.createResult();
		Iterator iter = resultsMap.keySet().iterator();
		while (iter != null && iter.hasNext()) {
			URI key = (URI) iter.next();
			Resultado resultado = resultsMap.get(key);
			if (resultado.usado) continue;
			Output output2 = process.createOutput(URI.create(BASE_URI + "Output_" + rdfID++), resultado.paramType);
			output2.setLabel(resultado.label);
			saidas.put(output2.getURI(), key);
			result.addBinding(output2, resultado.perform, resultado.output);
		}

		FileOutputStream fos = new FileOutputStream("./plan/plano_" + contador++ + ".owl");
		ont.write(fos);
	}

}
